package com.bingxue.edu.management.education.service;

import cn.hutool.core.util.ArrayUtil;
import com.bingxue.edu.common.enums.ChangeTypeEnum;
import com.bingxue.edu.common.enums.EmployeeTypeEnum;
import com.bingxue.edu.common.enums.EnrollmentStatusEnum;
import com.bingxue.edu.common.enums.StudentClassEnum;
import com.bingxue.edu.framework.common.model.PageQuery;
import com.bingxue.edu.framework.common.model.Pagination;
import com.bingxue.edu.framework.common.util.SpringContextHolder;
import com.bingxue.edu.framework.common.util.ValidationUtils;
import com.bingxue.edu.framework.mybatis.base.BaseService;
import com.bingxue.edu.management.education.mapper.EnrollmentMapper;
import com.bingxue.edu.management.education.mapper.StudentMapper;
import com.bingxue.edu.management.education.model.entity.ClassInfo;
import com.bingxue.edu.management.education.model.entity.EnrollChangeRecord;
import com.bingxue.edu.management.education.model.entity.Enrollment;
import com.bingxue.edu.management.education.model.entity.Student;
import com.bingxue.edu.management.education.model.query.EnrollClassQuery;
import com.bingxue.edu.management.education.model.query.EnrollLessonQuery;
import com.bingxue.edu.management.education.model.query.EnrollmentQuery;
import com.bingxue.edu.management.education.model.req.EnrollSellerUpdateReq;
import com.bingxue.edu.management.education.model.resp.ClassDetailResp;
import com.bingxue.edu.management.education.model.resp.EnrollClassResp;
import com.bingxue.edu.management.education.model.resp.EnrollLessonResp;
import com.bingxue.edu.management.education.model.resp.EnrollmentDetailResp;
import com.bingxue.edu.management.education.model.resp.EnrollmentResp;
import com.bingxue.edu.management.event.ClassCanceledEvent;
import com.bingxue.edu.management.event.ClassChangedEvent;
import com.bingxue.edu.management.event.EnrollPassedEvent;
import com.bingxue.edu.management.event.LessonCanceledEvent;
import com.bingxue.edu.management.event.LessonChangedEvent;
import com.bingxue.edu.management.shop.model.entity.Order;
import com.bingxue.edu.management.shop.model.entity.OrderItem;
import com.bingxue.edu.management.shop.service.SellRecordService;
import com.bingxue.edu.management.system.model.entity.Employee;
import com.bingxue.edu.management.system.service.EmployeeService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

import static com.bingxue.edu.management.education.model.entity.table.ClassInfoTableDef.CLASS_INFO;
import static com.bingxue.edu.management.education.model.entity.table.EnrollmentTableDef.ENROLLMENT;
import static com.bingxue.edu.management.education.model.entity.table.LessonStudentTableDef.LESSON_STUDENT;
import static com.bingxue.edu.management.education.model.entity.table.LessonTableDef.LESSON;
import static com.bingxue.edu.management.education.model.entity.table.StudentTableDef.STUDENT;
import static com.bingxue.edu.management.shop.model.entity.table.OrderItemTableDef.ORDER_ITEM;

/**
 * 报名信息业务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class EnrollmentService extends BaseService<EnrollmentMapper, Enrollment> {

    @Lazy
    @Resource
    private EmployeeService employeeService;
    private final EnrollChangeRecordService enrollChangeRecordService;
    private final StudentMapper studentMapper;
    private final LessonStudentService lessonStudentService;
    private final SellRecordService sellRecordService;
    private final ClassInfoService classInfoService;

    /**
     * 根据学生id和班级状态查询对应报名班级信息列表
     * @param query 查询条件
     * @return 报名班级列表
     */
    public <R> Pagination<R> getEnrollClassPage(EnrollClassQuery query, PageQuery pageQuery, Class<R> asType) {
        QueryWrapper queryWrapper = buildQueryWrapper(query);
        Page<R> page = this.getMapper().paginateWithRelationsAs(pageQuery.toPage(), queryWrapper, asType);
        return Pagination.of(page);
    }

    /**
     * 根据学生id和班级状态查询对应报名班级信息列表
     * @return 报名班级列表
     */
    public List<EnrollClassResp> getEnrollClassList(EnrollClassQuery query) {
        QueryWrapper queryWrapper = buildQueryWrapper(query);
        return this.getMapper().selectListWithRelationsByQueryAs(queryWrapper, EnrollClassResp.class);
    }

    /**
     * 根据学生id和班级状态查询对应报名班级信息列表
     * @param query 查询条件
     * @return 报名班级列表
     */
    public EnrollClassResp getEnrollClass(EnrollClassQuery query) {
        QueryWrapper queryWrapper = buildQueryWrapper(query);
        return this.getMapper().selectOneWithRelationsByQueryAs(queryWrapper, EnrollClassResp.class);
    }

    private QueryWrapper buildQueryWrapper(EnrollClassQuery query) {
        return QueryWrapper.create()
                .select(
                        CLASS_INFO.DEFAULT_COLUMNS,
                        ENROLLMENT.DEFAULT_COLUMNS
                )
                .from(ENROLLMENT)
                .join(CLASS_INFO).on(ENROLLMENT.CLASS_ID.eq(CLASS_INFO.ID))
                .where(ENROLLMENT.ID.eq(query.getEnrollmentId()))
                    .and(ENROLLMENT.STUDENT_ID.eq(query.getStudentId()))
                    .and(ENROLLMENT.STATUS.eq(query.getEnrollStatus()))
                    .and(CLASS_INFO.CLASS_STATUS.in(query.getClassStatus()))
                .orderBy(ENROLLMENT.ID.desc());
    }

    /**
     * 根据学生id和班级id查询报名课次列表
     * @param query 查询条件
     * @return 报名课次列表
     */
    public List<EnrollLessonResp> getEnrollLessonList(EnrollLessonQuery query) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .select(
                        ArrayUtil.addAll(LESSON_STUDENT.DEFAULT_COLUMNS, LESSON.DEFAULT_COLUMNS),
                        ORDER_ITEM.ORDER_ID
                )
                .from(LESSON_STUDENT)
                    .leftJoin(LESSON).on(LESSON_STUDENT.LESSON_ID.eq(LESSON.ID))
                    .leftJoin(ORDER_ITEM).on(LESSON_STUDENT.ORDER_ITEM_ID.eq(ORDER_ITEM.ID))
                .where(LESSON_STUDENT.STUDENT_ID.eq(query.getStudentId()))
                    .and(LESSON_STUDENT.ENROLLMENT_ID.eq(query.getEnrollmentId()))
                    .and(LESSON_STUDENT.STUDENT_CLASS_STATUS.eq(StudentClassEnum.NORMAL))
                .orderBy(LESSON.LESSON_INDEX.asc());
        return lessonStudentService.getMapper().selectListWithRelationsByQueryAs(queryWrapper, EnrollLessonResp.class
        );
    }

    /**
     * 根据班级和学生查询报名信息
     */
    public Enrollment getStudentEnrollment(String classId, String studentId) {
        return this.queryChain()
                .where(ENROLLMENT.CLASS_ID.eq(classId))
                .and(ENROLLMENT.STUDENT_ID.eq(studentId))
                .and(ENROLLMENT.STATUS.eq(EnrollmentStatusEnum.NORMAL))
                .one();
    }

    /**
     * 添加变更记录
     *
     * @param enrollment 报名信息
     * @param record     变更记录
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateEnrollment(Enrollment enrollment, EnrollChangeRecord record) {
        if (record.getChangeType() == ChangeTypeEnum.NEW_ENROLL) {
            // 新报名，保存记录
            this.save(enrollment);
            record.setEnrollmentId(enrollment.getId());
            enrollChangeRecordService.save(record);
            EnrollPassedEvent event = new EnrollPassedEvent(enrollment.getId(), record.getBusinessId());
            SpringContextHolder.publishEvent(event);
            return;
        }
        if (record.getChangeType() == ChangeTypeEnum.ADD_LESSON) {
            // 续费，更新信息
            this.updateById(enrollment);
            enrollChangeRecordService.save(record);
            return;
        }
        if (record.getChangeType() == ChangeTypeEnum.CHANGE_CLASS) {
            // 转班，更新信息
            this.updateChain()
                    .set(ENROLLMENT.CLASS_ID, record.getTargetClassId())
//                    .set(ENROLLMENT.REMAIN_CLASS_CHANGE_COUNT, ENROLLMENT.REMAIN_CLASS_CHANGE_COUNT.subtract(1))
                    .where(ENROLLMENT.ID.eq(enrollment.getId()))
                    .update();
            enrollChangeRecordService.save(record);
            ClassChangedEvent event = new ClassChangedEvent(record.getId());
            SpringContextHolder.publishEvent(event);
            return;
        }
        if (record.getChangeType() == ChangeTypeEnum.CHANGE_LESSON) {
            // 调课，更新信息
            this.increaseLessonChangeCount(enrollment.getId(), -1);
            enrollChangeRecordService.save(record);
            LessonChangedEvent event = new LessonChangedEvent(record.getId());
            SpringContextHolder.publishEvent(event);
            return;
        }
        if (record.getChangeType() == ChangeTypeEnum.CANCEL_CLASS) {
            // 退班
            this.updateChain()
                    .set(ENROLLMENT.CANCEL_LESSON_COUNT, ENROLLMENT.CANCEL_LESSON_COUNT.add(record.getLessonLength()))
                    .set(ENROLLMENT.STATUS, EnrollmentStatusEnum.CANCELED)
                    .where(ENROLLMENT.ID.eq(enrollment.getId()))
                    .update();
            enrollChangeRecordService.updateById(record);
            ClassCanceledEvent event = new ClassCanceledEvent(record.getId());
            SpringContextHolder.publishEvent(event);
            return;
        }
        if (record.getChangeType() == ChangeTypeEnum.CANCEL_LESSON) {
            // 退课
            this.updateChain()
                    .set(ENROLLMENT.CANCEL_LESSON_COUNT, ENROLLMENT.CANCEL_LESSON_COUNT.add(record.getLessonLength()))
                    .where(ENROLLMENT.ID.eq(enrollment.getId()))
                    .update();
            enrollChangeRecordService.updateById(record);
            LessonCanceledEvent event = new LessonCanceledEvent(record.getId());
            SpringContextHolder.publishEvent(event);
            return;
        }

    }

    /**
     * 初始化报名信息
     *
     * @param order     订单信息
     * @param orderItem 订单项
     * @param classInfo 班级信息
     */
    public Enrollment initEnrollment(Order order, OrderItem orderItem, ClassInfo classInfo) {
        Enrollment enrollment = new Enrollment();
        enrollment.setStudentId(order.getStudentId());
        enrollment.setClassId(orderItem.getClassId());
        enrollment.setEnrollLessonCount(orderItem.getLessonIndexes().size());
        enrollment.setCompletedLessonCount(0);
        enrollment.setCancelLessonCount(0);
        enrollment.setRemainClassChangeCount(-1);
        enrollment.setRemainLessonChangeCount(classInfo.getLessonChangeLimit());
        enrollment.setStatus(EnrollmentStatusEnum.NORMAL);
        return enrollment;
    }

    public Page<EnrollmentResp> getEnrollmentPage(EnrollmentQuery query, PageQuery pageQuery) {
        QueryWrapper queryWrapper = buildQueryWrapper(query);
        return this.getMapper().paginateWithRelationsAs(pageQuery.toPage(), queryWrapper, EnrollmentResp.class);
    }

    public List<EnrollmentResp> getEnrollmentList(EnrollmentQuery query) {
        QueryWrapper queryWrapper = buildQueryWrapper(query);
        return this.getMapper().selectListWithRelationsByQueryAs(queryWrapper, EnrollmentResp.class);
    }

    public EnrollmentDetailResp getDetailById(String enrollmentId) {
        EnrollmentDetailResp enrollmentResp = this.getMapper().selectOneWithRelationsByIdAs(enrollmentId, EnrollmentDetailResp.class);
        ValidationUtils.throwIfNull(enrollmentResp, "报名信息不存在");
        // 学生信息
        Student student = studentMapper.selectOneById(enrollmentResp.getStudentId());
        enrollmentResp.setStudent(student);
        // 班级信息
        ClassDetailResp classDetailResp = classInfoService.getDetailById(enrollmentResp.getClassId());
        enrollmentResp.setClassInfo(classDetailResp);
        // 课次信息
        EnrollLessonQuery enrollLessonQuery = new EnrollLessonQuery();
        enrollLessonQuery.setStudentId(student.getId());
        enrollLessonQuery.setEnrollmentId(enrollmentId);
        List<EnrollLessonResp> enrollLessonList = this.getEnrollLessonList(enrollLessonQuery);
        enrollmentResp.setEnrollLessonList(enrollLessonList);

        return enrollmentResp;
    }

    /**
     * 添加销售顾问
     * 已经设置过不能再次设置
     * @param req 添加销售顾问请求
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateSeller(EnrollSellerUpdateReq req) {
        Enrollment enrollment = this.getById(req.getEnrollmentId());
        ValidationUtils.throwIfNull(enrollment, "报名记录不存在");
        ValidationUtils.throwIfEqual(enrollment.getStatus(), EnrollmentStatusEnum.CANCELED, "无法操作已退班记录");
        ValidationUtils.throwIfNotNull(enrollment.getSellerId(), "无法重复设置销售顾问");

        Employee employee = employeeService.getById(req.getSellerId());
        ValidationUtils.throwIfNull(employee, "销售顾问不存在");
        ValidationUtils.throwIfNotEqual(employee.getType(), EmployeeTypeEnum.SELLER, "员工不是销售顾问");

        //获取次月一号的时间
        LocalDateTime firstDayOfNextMonth = enrollment.getCreateTime()
                .plusMonths(1)          // 加一个月
                .withDayOfMonth(1)      // 设置为当月的第一天
                .withHour(23)            // 设置小时为23
                .withMinute(59)          // 设置分钟为59
                .withSecond(59)          // 设置秒为59
                .withNano(0);
        ValidationUtils.throwIf(LocalDateTime.now().isAfter(firstDayOfNextMonth),"超过规定的设置时间");

        enrollment.setSellerId(req.getSellerId());
        this.updateById(enrollment);

        sellRecordService.createEnrollSellRecord(enrollment, req.getSellerId());

        log.info("设置销售顾问成功");
    }

    /**
     * 修改剩余可调课次数
     * changeCount为负数则减1次
     */
    public void increaseLessonChangeCount(String enrollmentId, int changeCount) {
        this.updateChain()
                .set(ENROLLMENT.REMAIN_LESSON_CHANGE_COUNT, ENROLLMENT.REMAIN_LESSON_CHANGE_COUNT.add(changeCount))
                .where(ENROLLMENT.ID.eq(enrollmentId))
                .update();
    }

    private QueryWrapper buildQueryWrapper(EnrollmentQuery query) {
        return QueryWrapper.create()
                .select(
                        ENROLLMENT.DEFAULT_COLUMNS,
                        CLASS_INFO.DEFAULT_COLUMNS,
                        STUDENT.DEFAULT_COLUMNS
                )
                .from(ENROLLMENT)
                .leftJoin(CLASS_INFO).on(ENROLLMENT.CLASS_ID.eq(CLASS_INFO.ID))
                .leftJoin(STUDENT).on(ENROLLMENT.STUDENT_ID.eq(STUDENT.ID))
                .where(ENROLLMENT.STUDENT_ID.eq(query.getStudentId()))
                .and(ENROLLMENT.STATUS.in(query.getStatus()))
                .and(ENROLLMENT.SELLER_ID.eq(query.getSellerId()))
                .and(ENROLLMENT.CREATE_TIME.ge(query.getCreateDateFrom()))
                .and(ENROLLMENT.CREATE_TIME.lt(query.getCreateDateTo()))
                .and(ClassInfoService.buildCommonClassQueryCondition(query))
                .orderBy(ENROLLMENT.ID.desc());
    }
}
